《Android 基础(四十八)》ConstrainLayout【译】

原文地址

https://developer.android.google.cn/reference/android/support/constraint/ConstraintLayout

介绍

ConstrainLayout是一个允许开发者灵活地设置控件的位置和大小的ViewGroup。
只要你使用的Android系统版本在9以上,你便可以通过添加依赖的方式来使用ConstrainLayout.

使用

添加依赖

implementation ‘com.android.support.constraint:constraint-layout:1.1.3’

常用约束

相对定位(Relative positioning)

相对定位是ConstrainLayout构建布局的一种基本方式。相对定位约束可以帮助我们通过一个给定的Widget来摆放另外一个Widget。我们可以在横纵两个方向上约束Widget。

横向: left, right, start and end sides
纵向: top, bottom sides and text baseline

一般思路是将一个 Widget的给定侧约束到其他Widget的另一侧。

比如,把button B放置到button A的右侧(下图)

alt

实现可以如下

1
2
3
<Button android:id="@+id/buttonA" ... />
<Button android:id="@+id/buttonB" ...
app:layout_constraintLeft_toRightOf="@+id/buttonA" />

上述代码就是告诉系统,我们想让button B的左侧约束到button A的右侧。这样一个位置约束意味着,系统将让button A的右侧和button B的左侧在X轴上具有相同的位置。

此类相对位置属性还有很多,具体如下:
alt

  • layout_constraintLeft_toLeftOf
  • layout_constraintLeft_toRightOf
  • layout_constraintRight_toLeftOf
  • layout_constraintRight_toRightOf
  • layout_constraintTop_toTopOf
  • layout_constraintTop_toBottomOf
  • layout_constraintBottom_toTopOf
  • layout_constraintBottom_toBottomOf
  • layout_constraintBaseline_toBaselineOf
  • layout_constraintStart_toEndOf
  • layout_constraintStart_toStartOf
  • layout_constraintEnd_toStartOf
  • layout_constraintEnd_toEndOf

这些属性通过引用id来代表一个Widget,或者使用parent来代表父布局

1
2
<Button android:id="@+id/buttonB" ...
app:layout_constraintLeft_toLeftOf="parent" />

边距(Margins)

alt

如果设置了边距,则它们将应用于相应的约束,将边距强制设置为目标Widget和源Widget之间的空间。通常的布局边距属性就可以达到此效果。

  • android:layout_marginStart
  • android:layout_marginEnd
  • android:layout_marginLeft
  • android:layout_marginTop
  • android:layout_marginRight
  • android:layout_marginBottom

注意: 边距只能是正数或等于零,采用Dimension形式。

约束目标GONE后边距处理 (Margins when connected to a GONE widget)

当约束目标的可见性为View.GONE时,你还可以使用以下属性指示要使用的不同边距值:

  • layout_goneMarginStart
  • layout_goneMarginEnd
  • layout_goneMarginLeft
  • layout_goneMarginTop
  • layout_goneMarginRight
  • layout_goneMarginBottom

居中定位和位置偏差

ConstraintLayout的一个有用方面是它如何处理“不可能”的约束。例如,如果我们有如下代码:

1
2
3
4
5
<android.support.constraint.ConstraintLayout ...>
<Button android:id="@+id/button" ...
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"/>
</>

除非ConstraintLayout恰好具有与Button完全相同的大小,否则两个约束不能同时满足(双方都不能成为我们想要它们的位置)。

alt

在这种情况下,约束的作用就像是相反的力量将Widget拉平(上图);这样Widget最终将会在父容器中居中显示。这种使用方式在纵轴方向上同样适用。

偏差(Bias)

遇到这种相反的约束时的默认设置是使Widget居中;但是你可以使用偏差属性调整定位以使一侧偏向另一侧。

  • layout_constraintHorizontal_bias
  • layout_constraintVertical_bias

例如,如下代码将使左侧具有30%的偏差而不是默认的50%,使得左侧将更短,Widget更倾向于左侧(具体效果如下图):

1
2
3
4
5
6
<android.support.constraint.ConstraintLayout ...>
<Button android:id="@+id/button" ...
app:layout_constraintHorizontal_bias="0.3"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent/>
</>

alt

使用偏差属性,你可以制作更好地适应屏幕尺寸变化的用户界面。

环形定位(Circular positioning (Added in 1.1))

你可以以距离或者角度来约束一个Widget中心相对于另一个Widget的中心。这样我们就可以将Widget放置到一个圆环上。具体属性如下:

  • layout_constraintCircle : 引用widget ID
  • layout_constraintCircleRadius : 到另一个widget的距离
  • layout_constraintCircleAngle : widget需要摆放在哪个角度 (0-360)

alt
alt

1
2
3
4
5
<Button android:id="@+id/buttonA" ... />
<Button android:id="@+id/buttonB" ...
app:layout_constraintCircle="@+id/buttonA"
app:layout_constraintCircleRadius="100dp"
app:layout_constraintCircleAngle="45" />

可见性行为(Visibility behavior)

ConstraintLayout对于可见性为View.GONE的Widget有明确的处理方式。

GONE widget,一般情况下,将不会显示在界面上,同时也不再是布局中的一部分。

但就布局计算而言,GONE Widget仍然是其中的一部分,这是有很大区别的。

  • 对于布局传递,它们的尺寸将被视为零(基本上,它们将被解析为一个点)
  • 如果他们对其他Widget有限制,这些限制仍然会得到体现,但任何边距都会等于零

alt

这种特定的行为可以满足你在不破坏布局的情况下构建布局,只需要暂时将对应的Widget标记为GONE即可,这在构建简单的布局动画时是很有用的。

如上图,当A GONE后,B使用的左边距是B相对于A的边距。在某些情况下,这个边距可能并不是你所需要的(比如,A相对于容器存在20dp的左边距,B相对于A有40dp的左边距,当A被标记为GONE后,B相对于容器就会存在40dp的左边距)。因此,你可以指定在连接到的Widget标记为GONE时的margin作为备用边距值。具体看上一章节的【约束目标GONE后边距处理】。

尺寸约束(Dimensions constraints)

ConstraintLayout最小尺寸和最大尺寸

通过如下属性你可以给ConstrainLayout定义最大或是最小尺寸。

  • android:minWidth set the minimum width for the layout
  • android:minHeight set the minimum height for the layout
  • android:maxWidth set the maximum width for the layout
  • android:maxHeight set the maximum height for the layout

当其尺寸设置为WRAP_CONTENT时,这些最小和最大尺寸将会被ConstraintLayout使用到。

Widgets尺寸约束

Widgets的尺寸需要通过如下三种方式设置android:layout_widthandroid:layout_height来明确。

  • 使用一个明确的尺寸大小 (数字值如123dp或者是一个尺寸引用)
  • 使用WRAP_CONTENT, 让控件自己计算其大小
  • 使用0dp, 等价于 “MATCH_CONSTRAINT”

alt

前两种设置的效果和其他布局一样。最后一个将以匹配所设置的约束的方式调整Widget的大小(上图中(a)wrap_content,(b)0dp)。如果设置来边距,它们也将被计算在内(上图中(c)0dp with margin)。

重要 针对ConstrainLayout中的Widget,我们不推荐使用MATCH_PARENT。我们可以通过使用MATCH_CONSTRAINT配合约束 Widget 的left/right或者top/bottom 到“parent”来定义类似的行为。

WRAP_CONTENT:强制执行约束 (Added in 1.1)

如果一个尺寸设置为WRAP_CONTENT,在1.1版本之前,他们将会被定义为数值类的尺寸大小,约束将不会限制结果尺寸。一般情况下这样已经足够满足需求并且运行速度也是很快的,但是在某些情况下,你可能想用WRAP_CONTENT来设置尺寸,同时也想强制约束来限制结果布局尺寸。这种情况下,你可以使用如下属性:

  • app:layout_constrainedWidth=”true|false”
  • app:layout_constrainedHeight=”true|false”

MATCH_CONSTRAINT(Added in 1.1)

当Widget的尺寸被设置为MATCH_CONSTRAINT时,默认的结果就是使用所有可用的空间。如下几个额外的属性可以被使用到:

  • layout_constraintWidth_min and layout_constraintHeight_min : 将为这个尺寸设置最小值
  • layout_constraintWidth_max and layout_constraintHeight_max : 将为这个尺寸设置最大值
  • layout_constraintWidth_percent and layout_constraintHeight_percent : 将按相对父布局的百分比来设置尺寸

最小值和最大值(Min and Max)

为min和max指示的值可以是Dp单位,也可以是“wrap”,它将使用与WRAP_CONTENT将执行的值相同的值

百分比尺寸(Percent dimension)

要使用百分比,你需要做如下配置:

  • 尺寸设置为MATCH_CONSTRAINT(0dp)
  • 默认值设置为percent** app:layout_constraintWidth_default=”percent”** 或者app:layout_constraintHeight_default=”percent”
    (备注: 在版本1.1-beta1 and 1.1-beta2中这些配置是需要的, 但是在后续的版本中只要百分比属性被定义,便不再需要这些配置)
  • 然后设置layout_constraintWidth_percent或者 layout_constraintHeight_percent属性值,范围0-1

比率

你可以定义Widget的宽高比例。为了实现这个效果,宽高中至少又一个设置为0dp(i.e.,MATCH_CONSTRAINT), 然后给** layout_constraintDimensionRatio**指定一个比例值,如下

1
2
3
<Button android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="1:1" />

这段代码将设置button的宽高一样。比例值可以通过如下两种方式设置:

  • float值, 代表宽高的比例
  • 比例值按照“width:height”的格式书写

在宽高都设置为MATCH_CONSTRAINT(0dp)时,我们仍然能够使用比例属性。在这种情况下,系统设置满足所有约束的最大尺寸并保持指定的纵横比。要根据另一个的尺寸约束一个特定边,可以预先附加“W,”“H,”分别约束宽度或高度。比如,一个尺寸被两个目标约束(宽度0dp并且在父布局居中),你可以通过在比例值前添加“W(约束宽度)”或者“H(约束高度)”,来指明约束宽度或者高度。

1
2
3
4
5
<Button android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="H,16:9"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"/>

如上代码,将按照16:9的比例来设置button的高度,而宽度将匹配父布局的约束。也就是这种情况下宽度:高度=16:9,由宽度来决定高度。

链(chain)

链在单个轴(水平或垂直)上提供组群行为。另一个轴可以独立约束

创建一个链

如果一组Widgets通过双向连接链接在一起,则它们被视为链。(下图展示的是一个由两个Widget组成的最小的链)

alt

链头

链由在链的第一个元素上设置的属性控制(我们可以将其视为链的“头”)

alt

头部是水平链的最左侧Widget,垂直链的最顶部Widget。

链间边距

如果在双向连接上指定了边距,则他们将会被计算在内。在扩散链的情况下,将从分配的空间中减去这些边距

链Style

在链的第一个元素上设置属性layout_constraintHorizo​​ntal_chainStylelayout_constraintVertical_chainStyle时,链的行为将根据指定的样式更改(默认为CHAIN_SPREAD

  • CHAIN_SPREAD – 元素将等间距散开(默认style)
  • Weighted链 – CHAIN_SPREAD 模式, 当一些Widgets设置为MATCH_CONSTRAINT,他们将被分配所有可用空间。
  • CHAIN_SPREAD_INSIDE – 相似地, 但是链的两端不会被分配空间。
  • CHAIN_PACKED – 链上元素会被打包在一起。子项的水平或垂直偏差属性将影响整个打包元素的定位。

alt

权重链

链的默认行为是在可用空间中平均分布元素。如果一个或多个元素使用MATCH_CONSTRAINT,则它们将使用可用的空白空间(他们之间平等分配)。
layout_constraintHorizo​​ntal_weightlayout_constraintVertical_weight属性将控制如何使用MATCH_CONSTRAINT在元素之间分配空间。例如,在使用MATCH_CONSTRAINT的包含两个元素的链上,第一个元素使用权重2,第二个元素使用权重1,第一个元素占用的空间将是第二个元素占用的空间的两倍。

边距和链(1.1版本)

在链中的元素上使用边距时,边距是相加的
例如,在水平链上,如果一个元素定义了10dp的右边距而下一个元素定义了5dp的左边距,则这两个元素之间产生的边距为15dp。
在计算链用于定位项目的剩余空间时,会同时考虑项目及其边距。剩余空间不包含边距。

虚拟助手(Virtual Helper objects)

除了之前详述的内在功能外,您还可以使用ConstraintLayout中的特殊帮助程序对象来帮助您进行布局。现在,Guideline可以帮助你创建相对于ConstraintLayout容器定位的水平和垂直Guideline。然后Widgets可以被约束到这些Guideline上。在1.1版本中,Barrier和Group也别加入进来。

优化器(in 1.1)

在1.1版本中,我们提供约束优化器。你可以通过将标记app:layout_optimizationLevel添加到ConstraintLayout元素来决定应用哪些优化。

  • none : 不做任何优化
  • standard : 默认值. 只优化 direct 和 barrier 约束
  • direct : 优化 direct 约束
  • barrier : 优化 barrier 约束
  • chain : 优化 chain 约束 (试验版)
  • dimensions : 优化 dimensions 测量 (试验版), 减少match constrains元素的测量次数。

此属性是一个掩码,因此您可以通过列出所需的优化来决定打开或关闭特定的优化。例如

1
app:layout_optimizationLevel="direct|barrier|chain"
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×